package net.za.cair.dip.model;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import net.za.cair.dip.util.AxiomManipulator;
import net.za.cair.dip.util.Utility;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;

import uk.ac.manchester.cs.owlapi.modularity.ModuleType;
import uk.ac.manchester.cs.owlapi.modularity.SyntacticLocalityModuleExtractor;

/*
 * Copyright (C) 2011, Centre for Artificial Intelligence Research
 *
 * Modifications to the initial code base are copyright of their
 * respective authors, or their employers as appropriate.  Authorship
 * of the modifications may be determined from the ChangeLog placed at
 * the end of this file.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

/**
 * Author: Kody Moodley<br>
 * Centre for Artificial Intelligence Research<br>
 * UKZN and CSIR<br>
 * Date: 10-Oct-2011<br><br>
 */

public class OntologyStructure {
	
	public DBox dBox;
	public BBox bBox;
	public SBox sBox;
	public ABox aBox;
	public OntologyStructure module;
	
	private Map<OWLAxiom, OWLAxiom> originalToTransformedAxioms;
	
	public OntologyStructure(){
		aBox = new ABox();
		dBox = new DBox();
		sBox = new SBox();
		bBox = new BBox();
		originalToTransformedAxioms = new HashMap<OWLAxiom, OWLAxiom>();
	}
	
	public OntologyStructure(OntologyStructure ontologyStructure){
		this.aBox = ontologyStructure.aBox;
		this.dBox = ontologyStructure.dBox;
		this.sBox = ontologyStructure.sBox;
		this.bBox = ontologyStructure.bBox;		
		this.module = ontologyStructure.module;
		this.originalToTransformedAxioms = ontologyStructure.originalToTransformedAxioms;
	}
	
	public OntologyStructure(OWLOntology ontology){
		aBox = new ABox();
		dBox = new DBox();
		sBox = new SBox();
		bBox = new BBox();
		
		//System.out.println(ontology.getABoxAxioms(true).size());
		
		aBox.addAll(ontology.getABoxAxioms(true));
		
		Set<OWLAxiom> axioms = new HashSet<OWLAxiom>(ontology.getLogicalAxioms());
		for (OWLAxiom a: axioms){
			if (Utility.getInstance().isDefeasible(a)){
				dBox.add(a);
			}
			else{
				if (a.isOfType(AxiomType.SUBCLASS_OF) || 
						a.isOfType(AxiomType.EQUIVALENT_CLASSES) ||
						a.isOfType(AxiomType.DISJOINT_CLASSES)){
					sBox.add(a);
				}
				else{
					bBox.add(a);
				}
			}
		}
	}
	
	public OWLOntology getProcessedOntology(OWLOntology ontology) throws OWLOntologyCreationException{
		aBox.addAll(ontology.getABoxAxioms(true));
		Set<OWLAxiom> axioms = new HashSet<OWLAxiom>(ontology.getLogicalAxioms());
		Set<OWLAxiom> resultAxioms = new HashSet<OWLAxiom>();
		OWLOntology result = null;
		for (OWLAxiom a: axioms){
			if (Utility.getInstance().isDefeasible(a)){
				OWLAxiom transA = getProcessedDAxiom(a); 
				originalToTransformedAxioms.put(a, transA);
				resultAxioms.add(transA);
			}
			else{
				OWLAxiom transA = getProcessedSAxiom(a); 
				originalToTransformedAxioms.put(a, transA);
				resultAxioms.add(transA);
			}
		}
		result = OWLManager.createOWLOntologyManager().createOntology(resultAxioms);
		return result;
	}
	
	public void computeModule(Set<OWLEntity> sig) throws OWLOntologyCreationException{
		SBox strictBox = getTransformed(this.sBox);
		Set<OWLAxiom> axioms = new HashSet<OWLAxiom>();
		axioms.addAll(aBox.getAxioms());
		axioms.addAll(dBox.getAxioms());
		axioms.addAll(bBox.getAxioms());
		axioms.addAll(strictBox.getAxioms());
		OWLOntologyManager ontologyManager = OWLManager.createOWLOntologyManager();
		SyntacticLocalityModuleExtractor sme = new SyntacticLocalityModuleExtractor(ontologyManager, ontologyManager.createOntology(axioms), ModuleType.STAR);
		Set<OWLAxiom> moduleAxioms = sme.extract(sig);
		module = new OntologyStructure(ontologyManager.createOntology(moduleAxioms));
	}
	
	private SBox getTransformed(SBox sbox){
		SBox result;
		Set<OWLAxiom> oldAxioms = sbox.getAxioms();
		Set<OWLAxiom> newAxioms = new HashSet<OWLAxiom>();
		for (OWLAxiom a: oldAxioms){
			newAxioms.add(getProcessedSAxiom(a));
		}
		result = new SBox(newAxioms);
		return result;
	}

	private OWLAxiom getProcessedDAxiom(OWLAxiom axiom){
		if (axiom.isOfType(AxiomType.EQUIVALENT_CLASSES)){	
			return AxiomManipulator.getDEquivToSubAxiom(axiom);
		}
		else if (axiom.isOfType(AxiomType.DISJOINT_CLASSES)){
			return AxiomManipulator.getDDisjToSubAxiom(axiom);
		}
		else{
			return axiom; 
		}
	}
	
	private OWLAxiom getProcessedSAxiom(OWLAxiom axiom){
		if (axiom.isOfType(AxiomType.SUBCLASS_OF)){
			return AxiomManipulator.getBottomNF(axiom);
		}
		return axiom;
	}
	
	public void addAxiom(OWLAxiom axiom){
		if (axiom.isOfType(AxiomType.ABoxAxiomTypes)){
			aBox.add(axiom);
		}
		else{
			if (axiom.isOfType(AxiomType.SUBCLASS_OF)){
				if (Utility.getInstance().isDefeasible(axiom)){
					dBox.add(axiom);
				}
				else{
					sBox.add(axiom);
				}
			}
			else if (axiom.isOfType(AxiomType.EQUIVALENT_CLASSES)){
				sBox.add(axiom);
			}
			else if (axiom.isOfType(AxiomType.DISJOINT_CLASSES)){
				sBox.add(axiom);
			}
			else{
				bBox.add(axiom);
			}
		}
	}
	
	public OWLAxiom getAlternate(OWLAxiom axiom){
		return originalToTransformedAxioms.get(axiom);
	}
	
	public Map<OWLAxiom, OWLAxiom> getTransformationMap(){
		return originalToTransformedAxioms;
	}
	
	public OWLClassExpression getConjunctionOfFullMaterialization(){
		OWLOntologyManager mngr = OWLManager.createOWLOntologyManager();
		OWLDataFactory dataF = mngr.getOWLDataFactory();
		Set<OWLClassExpression> sBoxMat = AxiomManipulator.getMaterialization(sBox);
		Set<OWLClassExpression> dBoxMat = AxiomManipulator.getMaterialization(dBox);
		
		OWLClassExpression s = dataF.getOWLObjectIntersectionOf(sBoxMat);
		OWLClassExpression d = dataF.getOWLObjectIntersectionOf(dBoxMat);
		
		return dataF.getOWLObjectIntersectionOf(s,d);
	}
	
	public OWLOntology asOWLOntology() throws OWLOntologyCreationException{
		Set<OWLAxiom> result = new HashSet<OWLAxiom>();
		for (OWLAxiom axiom: this.aBox.getAxioms()){
			result.add(axiom);
		}
		
		for (OWLAxiom axiom: this.bBox.getAxioms()){
			result.add(axiom);
		}
		
		for (OWLAxiom axiom: this.dBox.getAxioms()){
			result.add(axiom);
		}
		
		for (OWLAxiom axiom: this.sBox.getAxioms()){
			result.add(axiom);
		}
		
		return OWLManager.createOWLOntologyManager().createOntology(result);
	}
}
